use clap::Parser;
use std::sync::Arc;
use videoDownloader::{
    config::DownloadConfigBuilder,
    downloader::DownloaderFactory,
    progress::ProgressReporterFactory,
    retry::RetryStrategyFactory,
    utils::{generate_timestamped_filename, read_urls_with_filenames_from_file, is_double_clicked, show_console, UrlWithFilename},
    error::{DownloadError, DownloadResult},
};

#[derive(Parser)]
#[command(name = "yt-dlp-rs")]
#[command(about = "一个用 Rust 编写的 m3u8 下载器")]
struct Args {
    #[arg(short, long, help = "m3u8 播放列表的 URL (可选，不指定时从 urls.txt 读取)")]
    url: Option<String>,
    #[arg(short, long, help = "输出目录路径 (批量下载时使用，单个下载时为文件名)")]
    output: Option<String>,
    #[arg(short, long, default_value = "temp", help = "临时文件夹路径")]
    temp_dir: String,
    #[arg(short, long, default_value = "16", help = "并发下载数")]
    concurrent: usize,
    #[arg(short, long, default_value = "5", help = "下载失败重试次数")]
    retry: usize,
    #[arg(long, help = "SOCKS5 代理地址 (例如: socks5://127.0.0.1:1080)")]
    proxy: Option<String>,
    #[arg(long, default_value = "urls.txt", help = "批量下载的 URL 列表文件")]
    urls_file: String,
    #[arg(long, default_value = "mp4", help = "输出格式 (mp4, ts)")]
    _format: String,
    #[arg(long, help = "禁用自动转换，保持原始TS格式")]
    _no_convert: bool,
}

#[tokio::main]
async fn main() -> DownloadResult<()> {
    // 检查是否为双击启动，如果是则显示控制台
    if is_double_clicked() {
        show_console();
    }
    
    let args = Args::parse();
    
    println!("🚀 yt-dlp-rs - 优化版 Rust m3u8 下载器");
    
    // 决定下载模式：单个 URL 还是多个 URL
    let url_entries = get_urls(&args).await?;
    
    print_config_info(&args);
    
    // 构建配置和组件
    let config = DownloadConfigBuilder::new()
        .concurrent(args.concurrent)
        .retry_count(args.retry)
        .temp_dir(args.temp_dir.clone())
        .proxy_url(args.proxy.clone())
        .build()?;
    
    let downloader = create_downloader(config)?;
    
    // 执行下载
    download_urls_with_filenames(url_entries, &args, &downloader).await
}

async fn get_urls(args: &Args) -> DownloadResult<Vec<UrlWithFilename>> {
    if let Some(url) = &args.url {
        // 校验URL是否为有效的m3u8 URL
        if !is_valid_m3u8_url(url) {
            return Err(DownloadError::Url(format!("URL 不是有效的 m3u8 URL: {}", url)));
        }
        
        println!("📺 单个 URL 模式: {url}");
        Ok(vec![UrlWithFilename {
            url: url.clone(),
            filename: args.output.clone(),
        }])
    } else {
        println!("📁 多 URL 模式，从 {} 读取 URL 列表...", args.urls_file);
        match read_urls_with_filenames_from_file(&args.urls_file).await {
            Ok(url_entries) => {
                println!("📝 发现 {} 个有效 URL", url_entries.len());
                for (i, entry) in url_entries.iter().enumerate() {
                    if let Some(ref filename) = entry.filename {
                        println!("  {}. {} -> {}", i + 1, entry.url, filename);
                    } else {
                        println!("  {}. {} (使用时间戳文件名)", i + 1, entry.url);
                    }
                }
                Ok(url_entries)
            }
            Err(e) => {
                eprintln!("❌ 读取 URL 文件失败: {e}");
                eprintln!("ℹ️ 请在当前目录下创建 {} 文件，每行一个 m3u8 URL", args.urls_file);
                eprintln!("ℹ️ 格式: URL [空格] [可选文件名]");
                eprintln!("ℹ️ 或者使用 --url 参数指定单个 URL");
                Err(e)
            }
        }
    }
}

/// 检查URL是否为有效的m3u8 URL
fn is_valid_m3u8_url(url: &str) -> bool {
    // 检查URL是否以.m3u8结尾（最常见的情况）
    if url.to_lowercase().ends_with(".m3u8") {
        return true;
    }
    
    // 检查URL是否包含m3u8关键字
    if url.to_lowercase().contains("m3u8") {
        return true;
    }
    
    // 对于一些可能有效的URL，我们也可以接受
    // 例如，某些URL可能没有明确的m3u8扩展名，但仍然指向m3u8内容
    // 在这种情况下，我们让下载器尝试下载并检测内容
    false
}

fn print_config_info(args: &Args) {
    println!("⚡ 使用零拷贝下载和 1MB 缓存");
    println!("🚀 并发下载数: {} 个协程", args.concurrent);
    println!("🔄 重试次数: {} 次（如果 5 次都失败则停止下载）", args.retry);
    
    // 转换信息 - 当前版本总是转换为MP4格式
    println!("🎥 输出格式: MP4 (使用FFmpeg风格转换器)");
    println!("✨ 默认启用高质量FFmpeg风格TS→MP4转换器");
    
    if let Some(ref proxy) = args.proxy {
        println!("🔄 代理设置: {proxy}");
    } else {
        println!("🔴 直连模式（未使用代理）");
    }
    println!();
}

fn create_downloader(config: videoDownloader::config::DownloadConfig) -> DownloadResult<Arc<dyn videoDownloader::downloader::Downloader>> {
    // 使用只显示总进度条的进度报告器
    let progress_reporter = ProgressReporterFactory::create_total_only_reporter();
    let retry_strategy = RetryStrategyFactory::exponential_backoff(config.retry_count, 1000);
    
    let downloader = DownloaderFactory::create_dual_progress_downloader(
        config,
        Arc::from(progress_reporter),
        retry_strategy,
    )?;
    
    Ok(downloader)
}

async fn download_urls_with_filenames(
    url_entries: Vec<UrlWithFilename>,
    args: &Args,
    downloader: &Arc<dyn videoDownloader::downloader::Downloader>,
) -> DownloadResult<()> {
    let total_urls = url_entries.len();
    let mut success_count = 0;
    let mut failed_urls = Vec::new();
    
    // 逐个串行下载 URL
    for (index, entry) in url_entries.iter().enumerate() {
        println!("📋 ========== 下载进度: {}/{} ==========\n", index + 1, total_urls);
        
        // 生成输出文件名，优先使用URL指定的文件名
        let output_filename = generate_output_filename_for_entry(entry, total_urls, &args.output);
        
        println!("🚀 现在开始下载: {}", entry.url);
        println!("💾 输出文件: {}", output_filename);
        if let Some(ref specified_name) = entry.filename {
            println!("📝 指定文件名: {}", specified_name);
        }
        println!();
        
        match downloader.download(&entry.url, &output_filename).await {
            Ok(_) => {
                success_count += 1;
                println!("\n✅ {} 下载完成!", entry.url);
                println!("📋 最终文件: {}", output_filename);
                
                if total_urls > 1 {
                    println!();
                }
            }
            Err(e) => {
                // 检查错误类型，如果是网络错误或无效的m3u8格式，则忽略并继续
                match &e {
                    DownloadError::Network(_) | DownloadError::InvalidM3u8 => {
                        println!("\n⚠️  {} 下载失败: {}，已忽略", entry.url, e);
                        println!("⏭️  自动跳过，继续下载下一个...");
                        // 不将这类错误添加到失败列表中，因为我们选择忽略它们
                    }
                    _ => {
                        // 其他类型的错误仍然记录为失败
                        println!("\n❌ {} 下载出错: {}", entry.url, e);
                        println!("⏭️ 自动跳过，继续下载下一个...");
                        failed_urls.push((entry.url.clone(), e.to_string()));
                    }
                }
                if total_urls > 1 {
                    println!();
                }
            }
        }
    }
    
    print_results(total_urls, success_count, &failed_urls)
}

/// 为URL条目生成输出文件名
fn generate_output_filename_for_entry(
    entry: &UrlWithFilename,
    total_urls: usize,
    global_output: &Option<String>,
) -> String {
    // 下载阶段总是生成TS文件，然后根据需要转换
    let download_extension = "ts";
    
    if total_urls == 1 {
        // 单个URL：优先使用条目中的文件名，然后是全局输出设置
        if let Some(ref filename) = entry.filename {
            if filename.ends_with(".ts") {
                filename.clone()
            } else {
                format!("{}.{}", filename, download_extension)
            }
        } else if let Some(global_name) = global_output {
            if global_name.ends_with(".ts") {
                global_name.clone()
            } else {
                format!("{}.{}", global_name, download_extension)
            }
        } else {
            format!("output.{}", download_extension)
        }
    } else {
        // 多个URL：优先使用条目中的文件名，否则使用时间戳
        if let Some(ref filename) = entry.filename {
            if filename.ends_with(".ts") {
                filename.clone()
            } else {
                format!("{}.{}", filename, download_extension)
            }
        } else {
            let timestamp_name = generate_timestamped_filename();
            let base_name = timestamp_name.trim_end_matches(".ts");
            let final_name = format!("{}.{}", base_name, download_extension);
            
            if let Some(output_dir) = global_output {
                format!("{}/{}", output_dir, final_name)
            } else {
                final_name
            }
        }
    }
}

fn print_results(total_urls: usize, success_count: usize, failed_urls: &[(String, String)]) -> DownloadResult<()> {
    println!("📋 ================ 下载结果 ================\n");
    println!("✅ 成功下载: {success_count} 个");
    println!("❌ 失败下载: {} 个", failed_urls.len());
    println!("📈 总计: {total_urls} 个");
    
    if !failed_urls.is_empty() {
        println!();
        println!("❌ 失败的 URL 详情:");
        for (i, (url, error)) in failed_urls.iter().enumerate() {
            println!("  {}. {} - {}", i + 1, url, error);
        }
    }
    
    // 计算被忽略的URL数量（成功+失败应该等于总数，如果有差异则说明有被忽略的URL）
    let ignored_count = total_urls.saturating_sub(success_count + failed_urls.len());
    if ignored_count > 0 {
        println!("⏭️  已忽略: {} 个", ignored_count);
    }
    
    if success_count == total_urls {
        println!();
        println!("🎉 所有下载和转换成功完成!");
        Ok(())
    } else if success_count + failed_urls.len() == total_urls {
        // 有失败但没有被忽略的URL
        if success_count > 0 {
            println!();
            println!("⚠️  部分下载完成，请检查上述错误信息。");
            Ok(())
        } else {
            println!();
            println!("❌ 所有下载都失败了，请检查上述错误信息。");
            Err(DownloadError::Io(format!("{} 个 URL 下载失败", failed_urls.len())))
        }
    } else {
        // 有被忽略的URL
        if success_count > 0 {
            println!();
            println!("⚠️  部分下载完成（{} 个被忽略），请检查上述错误信息。", ignored_count);
            Ok(())
        } else {
            println!();
            println!("⚠️  所有URL都被忽略或下载失败，请检查上述信息。");
            // 如果所有URL都被忽略，不返回错误
            if failed_urls.is_empty() {
                Ok(())
            } else {
                Err(DownloadError::Io(format!("{} 个 URL 下载失败", failed_urls.len())))
            }
        }
    }
}
